import java.awt.Image;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;

import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;

import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;


public class Whater {
	 GL gl;
	 GLU glu;
	 int COUNT_DOT=21;
	 int DIST_BETWEEN_FIELDS = 160;
	 int ZOOM=4;
	 Vector3D mass[][]=new Vector3D[COUNT_DOT][COUNT_DOT];
	 private long start_time;
	 public static long cur_time=0;
		
	 private int[] tex1=new int[1];
	 private int[] tex2=new int[1];
	 private int list_id;//variable for static models
	 
	 private int shaderprogram;

	 Texture boxTexture1, boxTexture2;
	 private int vert_shader, frag_shader;
	 	 
	 public Whater(GL gl_, GLU glu_){
		 gl=gl_;
		 glu=glu_;
		 makeMass();
		 list_id = 0;
		 start_time = System.currentTimeMillis();
		 //LoadTexture();
		 loadShader();
		 CreateTexture(null);
	 }
	 
	 private void makeMass(){
		 for(int i=0; i<COUNT_DOT; ++i){
			 for(int j=0; j<COUNT_DOT; ++j)
			 {
				 mass[i][j]=new Vector3D();
				 mass[i][j].setXYZ((float)i*ZOOM, (float)j*ZOOM, 0f);
			 }
		 }
	 }
	 
	 private void CreateTexture(Image image)
	 {
		 URL imageURL= this.getClass().getResource(
				 "ground1.png");
	        
		 TextureData data=null;
		 try {
			 data = TextureIO.newTextureData(
					 imageURL.openStream(),false, "png");
			 boxTexture1 = TextureIO.newTexture(data);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,tex1, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, tex1[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data.getWidth(),data.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data.getBuffer());
		 gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MAG_FILTER,GL.GL_LINEAR);
		 gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MIN_FILTER,GL.GL_LINEAR);       	
		 imageURL= this.getClass().getResource(
				 "world.png");
	            
		 data=null;
		 try {
			 data = TextureIO.newTextureData(
					 imageURL.openStream(),false, "png");
			 boxTexture2 = TextureIO.newTexture(data);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	            
	            
		 //gl.glEnable(GL.GL_TEXTURE_2D);
	     
		 gl.glGenTextures(1,tex2,0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, tex2[0]);
	     
		 gl.glTexImage2D(GL.GL_TEXTURE_2D,
				 0,GL.GL_RGBA,data.getWidth(),
				 data.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data.getBuffer());
		 gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MAG_FILTER,GL.GL_LINEAR);
		 gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MIN_FILTER,GL.GL_LINEAR);
	 }
	 
	 private void loadShader(){
		 vert_shader = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/phong.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/phong.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader);
	        
	        shaderprogram = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram, vert_shader);
	        gl.glAttachShader(shaderprogram, frag_shader);
	        gl.glLinkProgram(shaderprogram);
	        gl.glValidateProgram(shaderprogram);
	 }
	 
	 public void draw(Camera player, int HEIGHT, int WIDTH, int refraction){
		 if(refraction == 0) { 
			 gl.glActiveTexture(GL.GL_TEXTURE0);
		     gl.glBindTexture(GL.GL_TEXTURE_2D,tex1[0]-1);
		     gl.glCopyTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB,0,0, WIDTH,HEIGHT,0);
		     return;
		 }
		 else if(refraction == 1){
			 gl.glActiveTexture(GL.GL_TEXTURE1);
			 gl.glBindTexture(GL.GL_TEXTURE_2D,tex2[0]);
			 gl.glCopyTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB,0,0, WIDTH,HEIGHT,0);
		 }
		 
		 gl.glEnable(GL.GL_DEPTH_TEST);
		 gl.glUseProgram(shaderprogram);
		 setShader(player, HEIGHT);
		 if(list_id != 0){			 
			    gl.glCallList(list_id);
			 }
			 else {
				 list_id=gl.glGenLists(1);
				 gl.glNewList(list_id, GL.GL_COMPILE_AND_EXECUTE);
			 gl.glBegin(GL.GL_TRIANGLES);
			 
			 for(int i=0; i<COUNT_DOT-1; ++i)
			 {
				 for(int j=0; j<COUNT_DOT-1; ++j)
				 {
					 gl.glTexCoord2d(0f, 0f);
					 gl.glVertex3f(mass[i][j].x(), 
					 mass[i][j].y(), mass[i][j].z());
					 
					 gl.glTexCoord2d(0f, 1f);
					 gl.glVertex3f(mass[i+1][j].x(), 
					 mass[i+1][j].y(), mass[i+1][j].z());
					 
					 gl.glTexCoord2d(1f, 0f);                  //first field
					 gl.glVertex3f(mass[i][j+1].x(), 
					 mass[i][j+1].y(), mass[i][j+1].z());
					 
					 
					 gl.glTexCoord2d(1f, 1f);
					 gl.glVertex3f(mass[i+1][j+1].x(), 
					 mass[i+1][j+1].y(), mass[i+1][j+1].z());
					 

					 gl.glTexCoord2d(1f, 0f);
					 gl.glVertex3f(mass[i][j+1].x(), 
					 mass[i][j+1].y(), mass[i][j+1].z());
					 
					 gl.glTexCoord2d(0f, 1f);
					 gl.glVertex3f(mass[i+1][j].x(), 
					 mass[i+1][j].y(), mass[i+1][j].z());
					 
				 }
			 }
			 
			 for(int i=0; i<COUNT_DOT-1; ++i)
			 {
				 for(int j=0; j<COUNT_DOT-1; ++j)
				 {
					 gl.glTexCoord2d(0f, 0f);
					 gl.glVertex3f(mass[i][j].x(), 
					 mass[i][j].y()+DIST_BETWEEN_FIELDS, mass[i][j].z());
					 
					 gl.glTexCoord2d(0f, 1f);
					 gl.glVertex3f(mass[i+1][j].x(), 
					 mass[i+1][j].y()+DIST_BETWEEN_FIELDS, mass[i+1][j].z());
					 
					 gl.glTexCoord2d(1f, 0f);
					 gl.glVertex3f(mass[i][j+1].x(), 
					 mass[i][j+1].y()+DIST_BETWEEN_FIELDS, mass[i][j+1].z());   //second field
					 
					 
					 gl.glTexCoord2d(1f, 1f);
					 gl.glVertex3f(mass[i+1][j+1].x(), 
					 mass[i+1][j+1].y()+DIST_BETWEEN_FIELDS, mass[i+1][j+1].z());
					 

					 gl.glTexCoord2d(1f, 0f);
					 gl.glVertex3f(mass[i][j+1].x(), 
					 mass[i][j+1].y()+DIST_BETWEEN_FIELDS, mass[i][j+1].z());
					 
					 gl.glTexCoord2d(0f, 1f);
					 gl.glVertex3f(mass[i+1][j].x(), 
					 mass[i+1][j].y()+DIST_BETWEEN_FIELDS, mass[i+1][j].z());
					 
				 }
			 }
			gl.glEnd();
			gl.glEndList();
	     }
		 gl.glUseProgram(0);
	 }
	 
	 private void setShader(Camera player, int HEIGHT){
		 cur_time = (System.currentTimeMillis() - start_time);
//	        if(cur_time>10)
//	        	cur_time = 0;
	        //System.out.println(cur_time);
	        
	   //     gl.glTexParameterf( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);	        
	        
	        gl.glActiveTexture(GL.GL_TEXTURE0);
	        gl.glBindTexture(GL.GL_TEXTURE_2D, tex1[0]-1);
	        
	        gl.glActiveTexture(GL.GL_TEXTURE1);
	        gl.glBindTexture(GL.GL_TEXTURE_2D, tex2[0]);
	        
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "envMap"), 0);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "envMap2"), 1);
	    
	        int time = gl.glGetUniformLocation(shaderprogram, "time");
	        //System.out.println(time);
	        float tt = (float) (((cur_time)%100000)/1000.0 +2.0)/34f;
	        gl.glUniform1f(time, tt);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "waving"), 1);
	        gl.glUniform1f(gl.glGetUniformLocation(
	        		shaderprogram, "waterHeight"), 0f);
	        gl.glUniform1f(gl.glGetUniformLocation(
	        		shaderprogram, "wavenum"), 1f);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "numWaves"), 1);
	        gl.glUniform1f(gl.glGetUniformLocation(
	        		shaderprogram, "height"), (float) HEIGHT);
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram, "eyePos"), player.pos.x()
	        		, player.pos.y(), player.pos.z());
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram, "lightPos"), Atmosphere.sun.x(), Atmosphere.sun.y(), Atmosphere.sun.z());
	 }
	 
}
